package org.water.common.spring;

import java.io.IOException;
import java.lang.reflect.Method;

import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod;

public class CustomServletInvocableHandlerMethod extends ServletInvocableHandlerMethod {

	protected HandlerMethodReturnValueHandlerComposite returnValueHandlers;
	
	public CustomServletInvocableHandlerMethod(Object handler, Method method) {
		super(handler, method);
	}
	
	public CustomServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
		super(handlerMethod);
	}
	/**
	 * Register {@link HandlerMethodReturnValueHandler} instances to use to
	 * handle return values.
	 */
	@Override
	public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandlerComposite returnValueHandlers) {
		this.returnValueHandlers = returnValueHandlers;
	}
	/**
	 * 方法处理,返回值可以为空
	 */
	@Override
	public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		//super.invokeAndHandle(webRequest, mavContainer, providedArgs);
		Object resultType=getMethod().getGenericReturnType();
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if(resultType.equals(Void.TYPE))  //空返回
		{
			mavContainer.setRequestHandled(true);
			return;
		}
		if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		try {
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}
	
	/**
	 * Set the response status according to the {@link ResponseStatus} annotation.
	 */
	protected void setResponseStatus(ServletWebRequest webRequest) throws IOException {
		HttpStatus status = getResponseStatus();
		if (status == null) {
			return;
		}

		String reason = getResponseStatusReason();
		if (StringUtils.hasText(reason)) {
			webRequest.getResponse().sendError(status.value(), reason);
		}
		else {
			webRequest.getResponse().setStatus(status.value());
		}

		// To be picked up by RedirectView
		webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
	}
	protected String getReturnValueHandlingErrorMessage(String message, Object returnValue) {
		StringBuilder sb = new StringBuilder(message);
		if (returnValue != null) {
			sb.append(" [type=").append(returnValue.getClass().getName()).append("]");
		}
		sb.append(" [value=").append(returnValue).append("]");
		return getDetailedErrorMessage(sb.toString());
	}
}
